package com.ruoyi.system.es;


import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.mapping.*;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.search.Highlight;
import co.elastic.clients.json.JsonData;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.unit.Fuzziness;

import java.util.*;
import java.util.stream.Collectors;

/**
 * es操作相关的组装命令
 */
@Data
@Builder
public class ESBuilder {


    private Map<String, Property> mapping;
    //filter must must_not should.
    private BoolQuery.Builder bool;
    private Query.Builder query;
    //用作二级检索 filter.
    private List<Query> filterQuerys;
    private List<SortOptions> sorts;
    private Map<String, Aggregation> group;
    private Highlight.Builder highlight;
    private RangeQuery.Builder range;
    //排序分组关键字
    public static final String KEYWORD = ".keyword";
    //分组后的查询名称
    public static final String GROUP = "_group";

    /**
     * 日期类型
     * @param name
     * @param fromat
     * @return
     */
    public ESBuilder buildDate(String name, String fromat) {
        if (mapping == null) {
            mapping = new HashMap<>();
        }
        mapping.put(name, Property.of(property ->
                        property.date(DateProperty.of(p ->
                                        p.index(true).format(fromat)
                                )
                        )
                )
        );
        return this;
    }

    /**
     * 字符串类型
     * @param name
     * @return
     */
    public ESBuilder buildString(String name) {
        if (mapping == null) {
            mapping = new HashMap<>();
        }
        this.mapping.put(name, Property.of(property ->
                        property.text(TextProperty.of(textProperty ->
                                        textProperty.index(true)
                                                .analyzer("ik_max_word")
                                )
                        )
                )
        );
        return this;
    }

    /**
     * 数值类型
     * @param name
     * @return
     */
    public ESBuilder buildInteger(String name) {
        if (mapping == null) {
            mapping = new HashMap<>();
        }
        mapping.put(name, Property.of(property ->
                        property.integer(IntegerNumberProperty.of(p ->
                                        p.index(true)
                                )
                        )
                )
        );
        return this;
    }

    /**
     * keyword类型，排序聚合操作
     * @param name
     * @return
     */
    public ESBuilder buildKeyWord(String name) {
        if (mapping == null) {
            mapping = new HashMap<>();
        }
        mapping.put(name, Property.of(property ->
                        property.keyword(KeywordProperty.of(p ->
                                        p.index(true)
                                )
                        )
                )
        );
        return this;
    }

    /**
     * 不区分类型
     * @param name
     * @return
     */
    public ESBuilder buildKeyWordAndText(String name) {
        if (mapping == null) {
            mapping = new HashMap<>();
        }
        mapping.put(name, Property.of(property ->
                        property.text(TextProperty.of(p ->
                                        p.index(true).analyzer("ik_max_word")
                                                .fields("keyword", Property.of(pp -> pp.keyword(k -> k.index(true).ignoreAbove(10000))))
                                )
                        )
                )
        );
        return this;
    }

    /**
     * query 集合 Multimath
     * @param fieldList
     * @param value
     * @return
     */
    public ESBuilder buildQueryListMultimath(List<String> fieldList, String value) {
        if (filterQuerys == null) {
            filterQuerys = new ArrayList<>();
        }
        filterQuerys.add(Query.of(x -> x.multiMatch(builder -> builder.fields(fieldList).query(value).type(TextQueryType.Phrase).analyzer("ik_max_word"))));
        return this;
    }

    /**
     * query 集合 range
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQueryListRange(String field, String symbol, String value) {
        if (filterQuerys == null) {
            filterQuerys = new ArrayList<>();
        }
        RangeQuery.Builder range = new RangeQuery.Builder();
        range.field(field);
        if (symbol.equals("gt")) {
            range.gte(JsonData.of(value));
        }
        if (symbol.equals("lt")) {
            range.lte(JsonData.of(value));
        }
        filterQuerys.add(Query.of(x -> x.range(r -> range)));
        return this;
    }

    /**
     * must 条件：日期范围查询（修复方法）
     * @param field 日期字段名
     * @param startDate 开始日期（如 "2025-01-01"）
     * @param endDate 结束日期（如 "2025-12-31"）
     * @return ESBuilder
     */
    public ESBuilder buildBoolMustDateRange(String field, String startDate, String endDate) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }

        // 1. 构建 RangeQuery.Builder 并配置条件
        RangeQuery.Builder rangeBuilder = new RangeQuery.Builder().field(field);
        if (StringUtils.isNotBlank(startDate)) {
            rangeBuilder.gte(JsonData.of(startDate)); // 大于等于开始日期
        }
        if (StringUtils.isNotBlank(endDate)) {
            rangeBuilder.lte(JsonData.of(endDate)); // 小于等于结束日期
        }

        // 2. 关键修正：通过 build() 方法生成 RangeQuery 对象
        RangeQuery rangeQuery = rangeBuilder.build();

        // 3. 将 RangeQuery 转换为 Query 并添加到 must 条件
        bool.must(Query.of(q -> q.range(rangeQuery)));

        return this;
    }

    /**
     * must:所有条件必须同时成立
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildBoolMust(String field, String value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.must(builder -> builder.match(m -> m.field(field).query(v -> v.stringValue(value)).analyzer("ik_max_word")));
        return this;
    }

    /**
     * must 条件：字段不为空（exists 查询）
     * @param field 要判断的字段名（如 "filePath"、"create_time"）
     * @return ESBuilder
     */
    public ESBuilder buildBoolMustExists(String field) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }

        // 构建 exists 查询：判断字段是否存在且有值
        bool.must(Query.of(q -> q.exists(e -> e.field(field))));
        return this;
    }

    /**
     * must:所有条件必须同时成立
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildBoolMustNoIk(String field, String value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.must(builder -> builder.match(m -> m.field(field).query(v -> v.stringValue(value))));
        return this;
    }

    /**
     * must:多值查询 类似于in
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildBoolMustTerms(String field, List<String> value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        List<FieldValue> values = value.stream().map(FieldValue::of).collect(Collectors.toList());
        bool.must(builder -> builder.terms(t -> t.field(field).terms(tt -> tt.value(values))));
        return this;
    }

    /**
     * 单字段查询 精确
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQuerySingleMath(String field, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        query.term(builder->builder.field(field).value(value));
        return this;
    }


    /**
     * 多字段匹配
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQueryMutiMath(List<String> field, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        query.multiMatch(builder -> builder.fields(field).query(value).type(TextQueryType.Phrase).analyzer("ik_max_word").slop(1));
        return this;
    }

    public ESBuilder buildQueryMutiMath850(List<String> fields, String value) {
        // 确保 query 不为空（避免空指针）
        if (query == null) {
            query = new Query.Builder();
        }

        // 拆分关键词：去重、去空、去空格（兼容 Java 8+）
        List<String> keywords = Arrays.stream(value.split(","))
                .map(String::trim)
                .filter(keyword -> !keyword.isEmpty())
                .distinct()
                .collect(Collectors.toList());

        // 关键词非空时，构建 bool + term 查询（精准匹配 keyword 子字段）
        if (!keywords.isEmpty()) {
            query.bool(boolBuilder -> {
                for (String keyword : keywords) {
                    for (String field : fields) {
                        // 核心改动1：使用 field.keyword 子字段（如 a850 → a850.keyword）
                        String keywordField = field + ".keyword";
                        // 核心改动2：用 term 查询替代 multi_match（适配 keyword 字段，精准无兼容问题）
                        boolBuilder.should(shouldBuilder -> shouldBuilder.term(
                                buildTermQuery(keywordField, keyword)
                        ));
                    }
                }
                // 至少匹配 1 个关键词
                return boolBuilder.minimumShouldMatch("1");
            });
        }

        return this;
    }

    // 辅助方法：构建 term 查询（专门适配 keyword 字段）
    private TermQuery buildTermQuery(String field, String keyword) {
        return new TermQuery.Builder()
                .field(field)   // 目标字段：a850.keyword
                .value(keyword) // 精准匹配关键词（如 DB15、HB）
                .build();
    }

    public ESBuilder buildQueryMutiMath850bak(List<String> field, String value) {
        // 确保 query 不为空（避免空指针）
        if (query == null) {
            query = new Query.Builder();
        }

        // 拆分关键词（兼容 Java 8+）
        List<String> keywords = Arrays.stream(value.split(","))
                .map(String::trim)
                .filter(keyword -> !keyword.isEmpty())
                .distinct()
                .collect(Collectors.toList());

        // 关键词非空时，构建 bool 查询
        if (!keywords.isEmpty()) {
            // 外层 bool 构建器：lambda 需返回 boolBuilder 实例
            query.bool(boolBuilder -> {
                for (String keyword : keywords) {
                    // should 构建器：lambda 需返回 shouldBuilder 实例
                    boolBuilder.should(shouldBuilder ->
                            // multiMatch 构建器：lambda 需返回 multiBuilder 实例
                            shouldBuilder.multiMatch(multiBuilder ->
                                    multiBuilder.fields(field)
                                            .query(keyword)
                                            .type(TextQueryType.Phrase)
                                            .analyzer("ik_max_word")
                                            .slop(1)
                            )
                    );
                }
                // 设置最小匹配数后，返回 boolBuilder 实例
                return boolBuilder.minimumShouldMatch("1");
            });
        }

        return this;
    }

    /**
     * 多字段匹配
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQueryMutiMathGs(List<String> field, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        query.multiMatch(builder -> builder.fields(field).query(value).type(TextQueryType.PhrasePrefix).analyzer("ik_max_word").slop(2));
        return this;
    }

    /**
     * 多字段匹配
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQueryMutiMathDb15(List<String> field, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        query.multiMatch(builder -> builder.fields(field).query(value).type(TextQueryType.PhrasePrefix).analyzer("ik_max_word").slop(2));
        return this;
    }
    /**
     * 多字段匹配（适配模糊搜索，修复 PhrasePrefix 导致的无结果问题）
     * @param fields 目标字段（a100+a298）
     * @param value 搜索关键词（如 29741 铝电解）
     * @return ESBuilder
     */
    public ESBuilder buildQueryMutiMathDb15All(List<String> fields, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        if (fields.isEmpty() || StringUtils.isEmpty(value)) {
            return this;
        }

        // 核心逻辑：BestFields + Or 条件 + 中文分词，适配模糊搜索
        query.multiMatch(builder -> builder
                        .fields(fields) // 必须包含 a100（标准编号）和 a298（标准名称）
                        .query(value) // 用户输入的关键词
                        .type(TextQueryType.BestFields) // 分词匹配，取最高得分字段
                        .analyzer("ik_max_word") // 中文分词，适配“铝电解”等中文关键词
                        .operator(Operator.Or) // 匹配任一分词（29741 或 铝电解），扩大匹配范围
                        .slop(2) // 允许分词间有少量间隔（如“铝 电解”也能匹配）
                // 移除 fuzziness 配置，兼容低版本 Client，不影响核心功能
        );
        return this;
    }

    /**
     * 多字段匹配
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQueryMutiMathGb(List<String> field, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        query.multiMatch(builder -> builder.fields(field).query(value).type(TextQueryType.PhrasePrefix).analyzer("ik_max_word").slop(2));
        return this;
    }

    /**
     * 多字段匹配
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQueryMutiMathHb(List<String> field, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        query.multiMatch(builder -> builder.fields(field).query(value).type(TextQueryType.PhrasePrefix).analyzer("ik_max_word").slop(2));
        return this;
    }

    /**
     * 多字段匹配
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildQueryMutiMathMb(List<String> field, String value) {
        if (query == null) {
            query = new Query.Builder();
        }
        query.multiMatch(builder -> builder.fields(field).query(value).type(TextQueryType.PhrasePrefix).analyzer("ik_max_word").slop(2));
        return this;
    }


    /**
     * should 里面套bool查询
     * @param bb
     * @return
     */
    public ESBuilder buildBoolShould(BoolQuery.Builder bb) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.should(builder -> builder.bool(b -> bb));
        return this;
    }

    /**
     * must 里面套bool查询
     * @param bb
     * @return
     */
    public ESBuilder buildBoolMust(BoolQuery.Builder bb) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.must(builder -> builder.bool(b -> bb));
        return this;
    }

    /**
     * must 里面套query查询
     * @param qq
     * @return
     */
    public ESBuilder buildBoolMust(Query.Builder qq) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.must(builder -> qq);
        return this;
    }

    /**
     * should 里面套query查询（逻辑或：满足任意一个即可）
     * @param qq Query.Builder 实例
     * @return ESBuilder 自身（链式调用）
     */
    public ESBuilder buildBoolShouldG(Query.Builder qq) {
        if (bool == null) {
            bool = new BoolQuery.Builder(); // 若 bool 未初始化，先创建
        }
        bool.should(builder -> qq); // 往 should 子句添加查询条件
        return this;
    }

    /**
     * should:所有条件中成立一个即可
     * @param field
     * @param value
     * @return
     */
    public ESBuilder buildBoolShould(String field, String value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.should(builder -> builder.match(m -> m.field(field).query(v -> v.stringValue(value)).analyzer("ik_max_word")));
        return this;
    }

    public ESBuilder buildBoolShouldN(String field, String value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.should(builder -> builder.match(m -> m.field(field).query(v -> v.stringValue(value))));
        return this;
    }

    /**
     * 前缀查询should 类似于like %xxx
     * @param field
     * @return
     */
    public ESBuilder buildBoolShouldWildCard(String field, String value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.should(builder -> builder.wildcard(w -> w.field(field).value(value + "*")));
        return this;
    }

    /**
     * 前缀查询must 类似于like %xxx
     * @param field
     * @return
     */
    public ESBuilder buildBoolMustWildCard(String field, String value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.must(builder -> builder.wildcard(w -> w.field(field).value(value + "*")));
        return this;
    }

    /**
     * 排序
     * @param field
     * @param order
     * @return
     */
    public ESBuilder buildSort(String field, String order, boolean keyword) {
        if (StringUtils.isNotEmpty(field) && StringUtils.isNotEmpty(order)) {
            if (sorts == null) {
                sorts = new ArrayList<>();
            }
            SortOrder o = order.equals(SortOrder.Asc.jsonValue()) ? SortOrder.Asc : SortOrder.Desc;
            SortOptions.Builder sort = new SortOptions.Builder();
            sort.field(f -> f.field(field + (keyword ? KEYWORD : "")).order(o));
            sorts.add(sort.build());
        }
        return this;
    }

    /**
     * 排序 es提供的权重值排序
     * @param order
     * @return
     */
    public ESBuilder buildSortScore(String order) {
        if (StringUtils.isNotEmpty(order)) {
            if (sorts == null) {
                sorts = new ArrayList<>();
            }
            SortOptions.Builder sort = new SortOptions.Builder();
            SortOrder o = order.equals(SortOrder.Asc.jsonValue()) ? SortOrder.Asc : SortOrder.Desc;
            sort.score(s -> s.order(o));
            sorts.add(sort.build());
        }
        return this;
    }

    /**
     * 分组
     * @param field
     * @param keyword 是否需要加后缀，像string加keyword类型的在排序的时候需要加关键字，其他的不用，比如 keyword、long等
     * @return
     */
    public ESBuilder buildGroupBy(String field, boolean keyword) {
        if (StringUtils.isNotEmpty(field)) {
            if (group == null) {
                group = new HashMap<>();
            }
            Aggregation agg = Aggregation.of(a -> a.terms(t -> t.field(field + (keyword ? KEYWORD : ""))));
            group.put(field + GROUP, agg);
        }
        return this;
    }

    /**
     * 前缀查询must 类似于like %xxx
     * @param field
     * @return
     */
    public ESBuilder buildMustWildCard(String field, String value) {
        if (bool == null) {
            bool = new BoolQuery.Builder();
        }
        bool.must(builder -> builder.wildcard(w -> w.field(field).value(value + "*")));
        return this;
    }

    /**
     * 高亮显示
     * @param fields
     * @param preTag
     * @param postTag
     * @param numberOfFragments 高亮分段的数量，默认是5
     * @param fragmentSize 高亮字段内容长度 默认100
     * @return
     */
    public ESBuilder buildHighLight(String preTag, String postTag, Integer numberOfFragments, Integer fragmentSize, List<String> fields) {
        if (highlight == null) {
            highlight = new Highlight.Builder();
        }
        highlight.preTags(preTag).postTags(postTag).requireFieldMatch(false);
        if (numberOfFragments != null) {
            highlight.numberOfFragments(numberOfFragments);
        }
        if (fragmentSize != null) {
            highlight.fragmentSize(fragmentSize);
        }
        for (String field : fields) {
            highlight.fields(field, f -> f);
        }
        return this;
    }




}
